#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <zconf.h>
#include <stdlib.h>
#include "rtsp_service.h"
#include "CHashTable.h"

//端口映射图创建
static void PortMap_create(PortMap *portmap, unsigned short start_port, unsigned short port_pair) {
    portmap->startport = start_port;                    //保存开始端口
    portmap->pair_num = port_pair;                      //保存端口对数
    portmap->map = malloc(port_pair / 8);         //计算保存数组大小
    memset(portmap->map, 0, port_pair / 8);       //初始化储存区
}

//端口分配
static unsigned short PortMap_malloc(PortMap *portmap) {
    for (int i = 0; i < portmap->pair_num / 8; i++) {
        if (portmap->map[i] != 0xFF) {                                  //搜索串口
            for (int j = 0; j < 8; j++) {
                if (((portmap->map[i] >> j) & 0x01) == 0) {
                    portmap->map[i] = (portmap->map[i]) | (1 << j);
                    return (portmap->startport + (i * 8 + j) * 2);
                }
            }
        }
    }
    return 0;
}

//端口释放
static int PortMap_free(PortMap *portmap, unsigned short port) {
    unsigned int i = ((port - portmap->startport) / 2) / 8;
    unsigned int j = ((port - portmap->startport) / 2) % 8;
    portmap->map[i] = (portmap->map[i]) & (~(1 << j));
    return 0;
}


int RTSPService_init(RTSPService *service, char *ip, unsigned int port, int link_num, unsigned short start_port,
                     unsigned short port_pair) {
    int iFlags;


    memset(service, 0, sizeof(RTSPService));
    service->self = service;
    service->s_in.sin_family = AF_INET;
    service->s_in.sin_addr.s_addr = inet_addr(ip);
    service->s_in.sin_port = htons(port);

    //创建套接字
    service->s_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (service->s_socket == -1) {
        return RTSPSTRVICE_RET_ERR_SOCKET;
    }

    //设置为非阻塞模式
    iFlags = fcntl(service->s_socket, F_GETFL, 0);
    iFlags |= O_NONBLOCK;
    iFlags |= O_NDELAY;
    if (fcntl(service->s_socket, F_SETFL, iFlags) == -1) {
        return RTSPSERVICE_ERT_ERR_SET;
    }
    //端口复用
    setsockopt(service->s_socket, SOL_SOCKET, SO_REUSEADDR, (const void *) &iFlags, sizeof(iFlags));

    //绑定端口
    if (bind(service->s_socket, (struct sockaddr *) &service->s_in, sizeof(struct sockaddr_in)) == -1) {
        return RTSPSTRVICE_RET_ERR_BIND;
    }

    //监听
    if (listen(service->s_socket, link_num) == -1) {
        return RTSPSERVICE_ERT_ERR_LISTEN;
    }


    PortMap_create(&service->portmap, start_port, port_pair);               //创建端口池

    //内存池初始化
    ABMemoryPool_create(&service->rtsp_memory, sizeof(RTSPUnit));           //RTSP用户内存
    ABMemoryPool_create(&service->thread_memory, sizeof(TThreadThread));    //线程节点内存
    ABMemoryPool_create(&service->task_memory, sizeof(TThreadTask));        //任务节点内存
    ABMemoryPool_create(&service->list_node_memory, sizeof(TWListNode));    //链表节点内存
    ABMemoryPool_create(&service->rtpunit_memory, sizeof(RTPUnit));         //RTP资源内存
    ABMemoryPool_create(&service->rtpuser_memory, sizeof(RTPUser));         //RTP用户内存

    //初始化RTP资源操作互斥锁
    pthread_mutex_init(&service->rtp_list_lock, NULL);

    //RTSP单元初始化
    TWList_init(&service->rtsp_list);               //RTSP用户链表，一个连接添加一个节点
    TWList_init(&service->rtp_resource_list);       //RTP资源链表，N个连接可以共用一个资源


    //创建线程池
    TThreadPool_create(&service->thread_pool);

    //添加一个线程
    TThreadThread *thread = ABMemoryPool_block_malloc(&service->thread_memory); //申请线程内存
    TThreadPool_thread_add(&service->thread_pool, thread);                      //把线程添加到线程池

    //添加一个任务
    TThreadTask *task = ABMemoryPool_block_malloc(&service->task_memory);   //申请任务节点内存
    TThreadPool_task_set(task, RTSPService_accept_task, service);           //设置任务
    TThreadPool_task_add(&service->thread_pool, task);                      //把任务添加到线程池

    return RTSPSERVICE_RET_SUCCEED;
}

int RTSPService_accept(RTSPService *service) {
    socklen_t len = sizeof(struct sockaddr);
    service->a_socket = accept(service->s_socket, (struct sockaddr *) &(service->a_in), &len);
    if (service->a_socket == -1) {
        if (errno == EWOULDBLOCK) {
            //无连接
            return RTSPSERVICE_RET_WAIT;
        } else {
            //错误
            return PBUFSTR_RET_ERROR;
        }
    } else {
        //设为非阻塞模式
        int iFlags;
        iFlags = fcntl(service->a_socket, F_GETFL, 0);
        iFlags |= O_NONBLOCK;
        iFlags |= O_NDELAY;
        if (fcntl(service->a_socket, F_SETFL, iFlags) == -1) {
            return RTSPSERVICE_ERT_ERR_SET;
        }
        //有连接
        return RTSPSERVICE_RET_SUCCEED;
    }
}


int RTSPService_client_add(RTSPService *service) {

    RTSPUnit *unit = (RTSPUnit *) ABMemoryPool_block_malloc(&service->rtsp_memory); //申请RTSP用户内存
    RTSPUnit_init(unit, service, service->a_socket, &service->a_in);                //初始化RTSP用户,保存用户套接字和信息

    //将RTSP单元添加到列表
    TWListNode *node = ABMemoryPool_block_malloc(&service->list_node_memory);   //申请链表节点内存
    TWListNode_init(node, unit);                                                //初始化节点
    TWList_insert_node(&service->rtsp_list, node);                              //将RTSP用户添加链表

    //添加解析任务
    TThreadTask *task = ABMemoryPool_block_malloc(&service->task_memory);       //申请任务节点内存
    TThreadPool_task_set(task, RTSPUnit_resolver_task, unit);                   //配置任务
    TThreadPool_task_add(&service->thread_pool, task);                          //添加RTSP解析任务

    return RTSPSERVICE_RET_SUCCEED;
}

//在资源列表中寻找资源
static TWListNode *RTSPService_RTPUnit_search(RTSPService *service, char *url) {
    unsigned int hashkey;
    hashkey = CHashTable_ELFHash((char *) url);                                         //计算资源字符串哈希
    pthread_mutex_lock(&service->rtp_list_lock);                                        //上锁,防止寻找时被修改
    TWListNode *node = service->rtp_resource_list.headptr;                              //获取RTP资源节点
    while (node != 0) {                                                                 //哈希冲突往下寻找
        if (hashkey == ((RTPUnit *) node->dataptr)->url_hashkey) {
            if (strcmp((char *) url, ((RTPUnit *) node->dataptr)->url_buf) == 0) {
                pthread_mutex_unlock(&service->rtp_list_lock);
                return node;
            }
        }
        node = node->nextptr;
    }
    pthread_mutex_unlock(&service->rtp_list_lock);                                      //解锁
    return 0;
}

//添加新的资源
static TWListNode *RTSPService_RTPUnit_add(RTSPService *service, char *url) {

    TWListNode *node = ABMemoryPool_block_malloc(&service->list_node_memory);       //申请链表节点
    RTPUnit *unit = ABMemoryPool_block_malloc(&service->rtpunit_memory);            //申请资源节点
    unit->reference = 1;                                                            //标记节点引用
    unit->url_hashkey = CHashTable_ELFHash((char *) url);                           //计算哈希
    PBufStr_init(&unit->url, unit->url_buf, RTPUNIT_URL_SIZE);                      //初始化储存字符串
    PBufStr_str_save(&unit->url, url);                                              //保存资源路径
    TWListNode_init(node, unit);                                                    //初始化节点

    pthread_mutex_lock(&service->rtp_list_lock);                                    //上锁,防止有任务在读取
    TWList_insert_node(&service->rtp_resource_list, node);                          //插入节点
    pthread_mutex_unlock(&service->rtp_list_lock);                                  //解锁
    return node;
}

//释放资源列表
int RTSPService_RTPUnit_delete(RTSPService *service, TWListNode *node) {
    if (node == 0)
        return 0;
    pthread_mutex_lock(&service->rtp_list_lock);                            //上锁
    RTPUnit *unit = node->dataptr;                                          //获取RTP资源
    unit->reference--;//引用次数
    if (unit->reference == 0) {                                             //如果没有引用
        ABMemoryPool_block_free(&service->rtpunit_memory, unit);            //释放RTP资源
        TWList_delete_node(&service->rtp_resource_list, node);              //从删除节点
        ABMemoryPool_block_free(&service->list_node_memory, node);          //释放节点内存
    }
    pthread_mutex_unlock(&service->rtp_list_lock);                          //解锁
    return 0;
}

//从资源列表获取资源
TWListNode *RTSPService_RTPUnit_get(struct RTSPService *service, void *rtspunit) {
    struct RTSPUnit *unit = rtspunit;
    TWListNode *node;
    node = RTSPService_RTPUnit_search(service, (char *) unit->info.url_buf);        //如果搜索到资源，返回资源
    if (node != 0) {
        ((RTPUnit *) node->dataptr)->reference++;                                   //RTP资源引用加1
        return node;
    }
    node = RTSPService_RTPUnit_add(service, (char *) unit->info.url_buf);               //申请RTP资源空间
    RTPUnit *rtpunit = node->dataptr;
    FILE *fp = fopen("/home/linux/git/h264_to_rtp/record.h264", "rb");  //打开文件，测试
    if (fp == 0) {
        printf("file open error\n");
        exit(1);
    }
    RTPUnit_init(rtpunit, unit->service, fp);                                           //初始化RTP资源
    TThreadTask *task = ABMemoryPool_block_malloc(&unit->service->task_memory);         //初始化节点内存
    TThreadPool_task_set(task, (void *) RTPUnit_send_task, rtpunit);                    //设置任务
    TThreadPool_task_add(&unit->service->thread_pool, task);                            //将任务添加到线程池
    return node;
}


unsigned short RTSPService_PortMap_malloc(RTSPService *service) {
    return PortMap_malloc(&service->portmap);                               //申请端口
}

void RTSPService_PortMap_free(RTSPService *service, unsigned short port) {
    if (port == 0)
        return;
    PortMap_free(&service->portmap, port);                                  //释放端口
}

TWListNode *RTSPService_RTPUserNode_malloc(RTSPService *service) {
    TWListNode *node = ABMemoryPool_block_malloc(&service->list_node_memory);   //申请链表节点内存
    RTPUser *user = ABMemoryPool_block_malloc(&service->rtpuser_memory);         //申请RTP用户内存
    TWListNode_init(node, user);
    return node;
}

void RTSPService_RTPUserNode_free(RTSPService *service, TWListNode *user) {
    ABMemoryPool_block_free(&service->rtpuser_memory, user->dataptr);            //释放RTP用户内存
    ABMemoryPool_block_free(&service->list_node_memory, user);                   //释放链表节点内存
}

int RTSPService_accept_task(RTSPService *service) {
    int ret;

    ret = RTSPService_accept(service);          //判断是否有连接
    if (ret == RTSPSERVICE_RET_SUCCEED) {
        RTSPService_client_add(service);        //添加RTSP客户
        ret = TTHREADTASK_RET_RUN;
    } else if (ret == RTSPSERVICE_RET_WAIT) {
        ret = TTHREADTASK_RET_RUN;
    }
    return ret;
}